home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / bash / bash_110 / mint / bash110s.zoo / bash-1.10 / trap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-03  |  12.9 KB  |  520 lines

  1. /* trap.c -- Not the trap command, but useful functions
  2.    for manipulating those objects.  The trap command is
  3.    in builtins.c */
  4.  
  5. /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
  6.  
  7. This file is part of GNU Bash, the Bourne Again SHell.
  8.  
  9. Bash is free software; you can redistribute it and/or modify it under
  10. the terms of the GNU General Public License as published by the Free
  11. Software Foundation; either version 1, or (at your option) any later
  12. version.
  13.  
  14. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  15. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17. for more details.
  18.  
  19. You should have received a copy of the GNU General Public License along
  20. with Bash; see the file COPYING.  If not, write to the Free Software
  21. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22.  
  23. #include "trap.h"
  24. #include "shell.h"
  25.  
  26. extern int last_command_exit_value;
  27.  
  28. /* The list of things to do originally, before we started trapping. */
  29. SigHandler *original_signals[NSIG];
  30.  
  31. /* For each signal, a slot for a string, which is a command to be
  32.    executed when that signal is recieved.  The slot can also contain
  33.    DEFAULT_SIG, which means do whatever you were going to do before
  34.    you were so rudely interrupted, or IGNORE_SIG, which says ignore
  35.    this signal. */
  36. char *trap_list[NSIG];
  37.  
  38. /* A translation list so we can be polite to our users. */
  39. char *signal_names[NSIG];
  40.  
  41. /* A bitmap of signals received for which we have trap handlers. */
  42. int pending_traps[NSIG];
  43.  
  44. static int signal_names_initialized = 0;
  45.  
  46. initialize_traps ()
  47. {
  48.   register int i;
  49.  
  50.   if (!signal_names_initialized)
  51.     {
  52.       for (i = 1; i < NSIG; i++)
  53.         {
  54.       signal_names[i] = (char *)NULL;
  55.       pending_traps[i] = 0;
  56.         }
  57.  
  58.       /* `signal' 0 is what we do on exit. */
  59.       signal_names[0] = "EXIT";
  60.  
  61. #if defined (SIGHUP)        /* hangup */
  62.       signal_names[SIGHUP] = "SIGHUP";
  63. #endif
  64.  
  65. #if defined (SIGINT)        /* interrupt */
  66.       signal_names[SIGINT] = "SIGINT";
  67. #endif
  68.  
  69. #if defined (SIGQUIT)        /* quit */
  70.       signal_names[SIGQUIT] = "SIGQUIT";
  71. #endif
  72.  
  73. #if defined (SIGILL)        /* illegal instruction (not reset when caught) */
  74.       signal_names[SIGILL] = "SIGILL";
  75. #endif
  76.  
  77. #if defined (SIGTRAP)        /* trace trap (not reset when caught) */
  78.       signal_names[SIGTRAP] = "SIGTRAP";
  79. #endif
  80.  
  81. #if defined (SIGABRT)        /*  */
  82.       signal_names[SIGABRT] = "SIGABRT";
  83. #endif
  84.  
  85. #if defined (SIGIOT)        /* IOT instruction */
  86.       signal_names[SIGIOT] = "SIGIOT";
  87. #endif
  88.  
  89. #if defined (SIGEMT)        /* EMT instruction */
  90.       signal_names[SIGEMT] = "SIGEMT";
  91. #endif
  92.  
  93. #if defined (SIGFPE)        /* floating point exception */
  94.       signal_names[SIGFPE] = "SIGFPE";
  95. #endif
  96.  
  97. #if defined (SIGKILL)        /* kill (cannot be caught or ignored) */
  98.       signal_names[SIGKILL] = "SIGKILL";
  99. #endif
  100.  
  101. #if defined (SIGBUS)        /* bus error */
  102.       signal_names[SIGBUS] = "SIGBUS";
  103. #endif
  104.  
  105. #if defined (SIGSEGV)        /* segmentation violation */
  106.       signal_names[SIGSEGV] = "SIGSEGV";
  107. #endif
  108.  
  109. #if defined (SIGSYS)        /* bad argument to system call */
  110.       signal_names[SIGSYS] = "SIGSYS";
  111. #endif
  112.  
  113. #if defined (SIGPIPE)        /* write on a pipe with no one to read it */
  114.       signal_names[SIGPIPE] = "SIGPIPE";
  115. #endif
  116.  
  117. #if defined (SIGALRM)        /* alarm clock */
  118.       signal_names[SIGALRM] = "SIGALRM";
  119. #endif
  120.  
  121. #if defined (SIGTERM)        /* software termination signal from kill */
  122.       signal_names[SIGTERM] = "SIGTERM";
  123. #endif
  124.  
  125. #if defined (SIGCLD)        /* Like SIGCHLD.  */
  126.       signal_names[SIGCLD] = "SIGCLD";
  127. #endif
  128.  
  129. #if defined (SIGPWR)        /* Magic thing for some machines. */
  130.       signal_names[SIGPWR] = "SIGPWR";
  131. #endif
  132.  
  133. #if defined (SIGPOLL)        /* For keyboard input?  */
  134.       signal_names[SIGPOLL] = "SIGPOLL";
  135. #endif
  136.  
  137. #if defined (SIGURG)        /* urgent condition on IO channel */
  138.       signal_names[SIGURG] = "SIGURG";
  139. #endif
  140.  
  141. #if defined (SIGSTOP)        /* sendable stop signal not from tty */
  142.       signal_names[SIGSTOP] = "SIGSTOP";
  143. #endif
  144.  
  145. #if defined (SIGTSTP)        /* stop signal from tty */
  146.       signal_names[SIGTSTP] = "SIGTSTP";
  147. #endif
  148.  
  149. #if defined (SIGCONT)        /* continue a stopped process */
  150.       signal_names[SIGCONT] = "SIGCONT";
  151. #endif
  152.  
  153. #if defined (SIGCHLD)        /* to parent on child stop or exit */
  154.       signal_names[SIGCHLD] = "SIGCHLD";
  155. #endif
  156.  
  157. #if defined (SIGTTIN)        /* to readers pgrp upon background tty read */
  158.       signal_names[SIGTTIN] = "SIGTTIN";
  159. #endif
  160.  
  161. #if defined (SIGTTOU)        /* like TTIN for output if (tp->t_local<OSTOP) */
  162.       signal_names[SIGTTOU] = "SIGTTOU";
  163. #endif
  164.  
  165. #if defined (SIGIO)        /* input/output possible signal */
  166.       signal_names[SIGIO] = "SIGIO";
  167. #endif
  168.  
  169. #if defined (SIGXCPU)        /* exceeded CPU time limit */
  170.       signal_names[SIGXCPU] = "SIGXCPU";
  171. #endif
  172.  
  173. #if defined (SIGXFSZ)        /* exceeded file size limit */
  174.       signal_names[SIGXFSZ] = "SIGXFSZ";
  175. #endif
  176.  
  177. #if defined (SIGVTALRM)        /* virtual time alarm */
  178.       signal_names[SIGVTALRM] = "SIGVTALRM";
  179. #endif
  180.  
  181. #if defined (SIGPROF)        /* profiling time alarm */
  182.       signal_names[SIGPROF] = "SIGPROF";
  183. #endif
  184.  
  185. #if defined (SIGWINCH)        /* window changed */
  186.       signal_names[SIGWINCH] = "SIGWINCH";
  187. #endif
  188.  
  189. #if defined (SIGLOST)        /* resource lost (eg, record-lock lost) */
  190.       signal_names[SIGLOST] = "SIGLOST";
  191. #endif
  192.  
  193. #if defined (SIGUSR1)        /* user defined signal 1 */
  194.       signal_names[SIGUSR1] = "SIGUSR1";
  195. #endif
  196.  
  197. #if defined (SIGUSR2)        /* user defined signal 2 */
  198.       signal_names[SIGUSR2] = "SIGUSR2";
  199. #endif
  200.  
  201. #if defined (SIGMSG)    /* HFT input data pending */
  202.       signal_names[SIGMSG] = "SIGMSG";
  203. #endif
  204.  
  205. #if defined (SIGPWR)    /* power failure imminent (save your data) */
  206.       signal_names[SIGPWR] = "SIGPWR";
  207. #endif
  208.  
  209. #if defined (SIGDANGER)    /* system crash imminent */
  210.       signal_names[SIGDANGER] = "SIGDANGER";
  211. #endif
  212.  
  213. #if defined (SIGMIGRATE)    /* migrate process to another CPU */
  214.       signal_names[SIGMIGRATE] = "SIGMIGRATE";
  215. #endif
  216.  
  217. #if defined (SIGPRE)    /* programming error */
  218.       signal_names[SIGPRE] = "SIGPRE";
  219. #endif
  220.  
  221. #if defined (SIGGRANT)    /* HFT monitor mode granted */
  222.       signal_names[SIGGRANT] = "SIGGRANT";
  223. #endif
  224.  
  225. #if defined (SIGRETRACT)    /* HFT monitor mode retracted */
  226.       signal_names[SIGRETRACT] = "SIGRETRACT";
  227. #endif
  228.  
  229. #if defined (SIGSOUND)    /* HFT sound sequence has completed */
  230.       signal_names[SIGSOUND] = "SIGSOUND";
  231. #endif
  232.  
  233.       for (i = 0; i < NSIG; i++)
  234.     if (signal_names[i] == (char *)NULL)
  235.       {
  236.         signal_names[i] = (char *)xmalloc (10 + strlen ("SIGJUNK"));
  237.         sprintf (signal_names[i], "SIGJUNK(%d)", i);
  238.       }
  239.     }
  240.  
  241.  
  242.   trap_list[0] = (char *)NULL;
  243.  
  244.   for (i = 1; i < NSIG; i++)
  245.     {
  246.       trap_list[i] = (char *)DEFAULT_SIG;
  247.       original_signals[i] = (SigHandler *)signal (i, SIG_DFL);
  248.       signal (i, original_signals[i]);
  249.     }
  250. }
  251.  
  252. /* Return the print name of this signal. */
  253. char *
  254. signal_name (signal)
  255.      int signal;
  256. {
  257.   if (signal > NSIG)
  258.      return ("bad signal number");
  259.   else return (signal_names[signal]);
  260. }
  261.  
  262. /* Turn a string into a signal number, or a number into
  263.    a signal number.  If STRING was "2", "SIGINT", or "INT",
  264.    then (int)2 would be returned. */
  265. int
  266. decode_signal (string)
  267.      char *string;
  268. {
  269.   int sig;
  270.  
  271.   if (sscanf (string, "%d", &sig) == 1) {
  272.     if (sig < NSIG && sig >= 0)
  273.       return (sig);
  274.     else
  275.       return (NO_SIG);
  276.   }
  277.       
  278.   for (sig = 0; sig < NSIG; sig++)
  279.      if ((stricmp (string, signal_names[sig]) == 0) ||
  280.      (stricmp (string, &(signal_names[sig])[3]) == 0))
  281.        return (sig);
  282.  
  283.   return (NO_SIG);
  284. }
  285.  
  286. /* Non-zero when we catch a trapped signal. */
  287. static int catch_flag = 0;
  288.  
  289. #if !defined (USG) && !defined (USGr4)
  290. #define HAVE_BSD_SIGNALS
  291. #endif
  292.  
  293. run_pending_traps ()
  294. {
  295.   register int sig;
  296.   int old_exit_value;
  297.  
  298.   if (catch_flag == 0)        /* simple optimization */
  299.     return;
  300.  
  301.   catch_flag = 0;
  302.  
  303.   /* Preserve $? when running trap. */
  304.   old_exit_value = last_command_exit_value;
  305.  
  306.   for (sig = 0; sig < NSIG; sig++)
  307.     {
  308.       if (pending_traps[sig])
  309.     {
  310. #if defined (_POSIX_VERSION)
  311.       sigset_t set, oset;
  312.       sigemptyset (&set);
  313.       sigaddset (&set, sig);
  314.       sigprocmask (SIG_BLOCK, &set, &oset);
  315. #else
  316. #  if defined (HAVE_BSD_SIGNALS)
  317.       int oldmask = sigblock (sigmask (sig));
  318. #  endif
  319. #endif /* POSIX_VERSION */
  320.  
  321.       parse_and_execute (savestring (trap_list[sig]), "trap");
  322.       pending_traps[sig] = 0;
  323.  
  324. #if defined (_POSIX_VERSION)
  325.       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  326. #else
  327. #  if defined (HAVE_BSD_SIGNALS)
  328.       sigsetmask (oldmask);
  329. #  endif
  330. #endif /* POSIX_VERSION */
  331.     }
  332.     }
  333.  
  334.   last_command_exit_value = old_exit_value;
  335. }
  336.  
  337. sighandler
  338. trap_handler (sig)
  339.      int sig;
  340. {
  341.   extern int interrupt_immediately;
  342.  
  343.   if ((sig >= NSIG) ||
  344.       (trap_list[sig] == (char *)DEFAULT_SIG) ||
  345.       (trap_list[sig] == (char *)IGNORE_SIG))
  346.     programming_error ("trap_handler: Bad signal %d", sig);
  347.   else
  348.     {
  349.  
  350. #if defined (USG) && !defined (HAVE_BSD_SIGNALS)
  351.       signal (sig, trap_handler);
  352. #endif /* USG && !HAVE_BSD_SIGNALS */
  353.  
  354.       catch_flag = 1;
  355.       pending_traps[sig]++;
  356.  
  357.       if (interrupt_immediately)
  358.     run_pending_traps ();
  359.     }
  360. #if !defined (VOID_SIGHANDLER)
  361.   return (0);
  362. #endif /* VOID_SIGHANDLER */
  363. }
  364.  
  365. /* Set SIG to call STRING as a command. */
  366. void
  367. set_signal (sig, string)
  368.      int sig;
  369.      char *string;
  370. {
  371.   void change_signal ();
  372.  
  373.   /* A signal ignored on entry to the shell cannot be trapped or reset, but
  374.      no error is reported when attempting to do so.  -- Posix.2 */
  375.   if (original_signals[sig] == SIG_IGN)
  376.     return;
  377.  
  378. #if defined (SIGCHLD)
  379.   /* Don't change the function that catches SIGCHLD, but store the command
  380.      to be executed.  It will be run from jobs.c: flush_child(). */
  381.   if (sig &&
  382.       sig != SIGINT &&
  383.       sig != SIGCHLD)
  384. #else
  385.   if (sig && sig != SIGINT)
  386. #endif /* SIGCHLD */
  387.     signal (sig, SIG_IGN);
  388.  
  389.   change_signal (sig, savestring (string));
  390.  
  391. #if defined (SIGCHLD)
  392.   /* Don't change the function that catches SIGCHLD, but store the command
  393.      to be executed.  It will be run from jobs.c: flush_child().  Do the
  394.      same thing for SIGINT; the trap commands are run from
  395.      run_interrupt_trap (), which is called from throw_to_top_level (). */
  396.   if (sig &&
  397.       sig != SIGINT &&
  398.       sig != SIGCHLD)
  399. #else
  400.   if (sig && sig != SIGINT)
  401. #endif /* SIGCHLD */
  402.     signal (sig, trap_handler);
  403. }
  404.  
  405. /* If SIG has a string assigned to it, get rid of it.  Then give it
  406.    VALUE. */
  407. void
  408. change_signal (sig, value)
  409.      int sig;
  410.      char *value;
  411. {
  412.   if ((((int)trap_list[sig]) > 0) && (trap_list[sig] != (char *)IGNORE_SIG))
  413.     free (trap_list[sig]);
  414.   trap_list[sig] = value;
  415. }
  416.  
  417. /* Restore the default action for SIG; i.e., the action the shell
  418.    would have taken before you used the trap command. */
  419. void
  420. restore_default_signal (sig)
  421.      int sig;
  422. {
  423. #if defined (SIGCHLD)
  424.   /* Don't allow the signal catchers for SIGINT or SIGCHLD
  425.      to be overridden. */
  426.   if (sig != SIGINT && sig != SIGCHLD)
  427. #else
  428.   if (sig != SIGINT)
  429. #endif /* !SIGCHLD */
  430.     signal (sig, original_signals[sig]);
  431.  
  432.   change_signal (sig, (char *)DEFAULT_SIG);
  433. }
  434.  
  435. /* Make this signal be ignored. */
  436. void
  437. ignore_signal (sig)
  438.      int sig;
  439. {
  440. #ifdef SIGCHLD
  441.   /* Don't allow the SIGCHLD signal catcher to be overridden. */
  442.   if (sig != SIGCHLD)
  443. #endif
  444.     signal (sig, SIG_IGN);
  445.   change_signal (sig, (char *)IGNORE_SIG);
  446. }
  447.  
  448. /* Handle the calling of "trap 0".  The only sticky situation is when
  449.    the command to be executed includes an "exit".  This is why we have
  450.    to provide our own place for top_level to jump to. */
  451. void
  452. run_exit_trap ()
  453. {
  454.   if ((trap_list[0] != (char *)DEFAULT_SIG) &&
  455.       (trap_list[0] != (char *)IGNORE_SIG))
  456.     {
  457.       char *trap_command = savestring (trap_list[0]);
  458.       int code, old_exit_value;
  459.  
  460.       old_exit_value = last_command_exit_value;
  461.       change_signal (0, (char *)NULL);
  462.       code = setjmp (top_level);
  463.  
  464.       if (code == 0)
  465.     parse_and_execute (trap_command, "trap");
  466.  
  467.       last_command_exit_value = old_exit_value;
  468.     }
  469. }
  470.       
  471. /* Reset all trapped signals to their original values.  Signals set to be
  472.    ignored with trap '' SIGNAL should be ignored, so we make sure that they
  473.    are. */
  474. void
  475. restore_original_signals ()
  476. {
  477.   register int i;
  478.  
  479.   for (i = 0; i < NSIG; i++)
  480.     {
  481.       if (trap_list[i] != (char *)DEFAULT_SIG)
  482.     {
  483.       if (trap_list[i] == (char *)IGNORE_SIG)
  484.         signal (i, SIG_IGN);
  485.       else
  486.         restore_default_signal (i);
  487.     }
  488.       else
  489.     {
  490.       /* If it's one of the signals the shell handles specially,
  491.          make sure it gets set back to the value it had when the
  492.          shell was started. */
  493.       if (i == SIGINT || i == SIGQUIT || i == SIGTERM)
  494.         restore_default_signal (i);
  495.     }
  496.     }
  497. }
  498.  
  499. /* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
  500.    declared here to localize the trap functions. */
  501. run_interrupt_trap ()
  502. {
  503.   char *command, *saved_command;
  504.   int old_exit_value;
  505.  
  506.   if ((trap_list[SIGINT] != (char *) DEFAULT_SIG) &&
  507.       (trap_list[SIGINT] != (char *) IGNORE_SIG))
  508.     {
  509.       command = savestring (trap_list[SIGINT]);
  510.  
  511.       old_exit_value = last_command_exit_value;
  512.       saved_command = trap_list[SIGINT];
  513.       unwind_protect_string (trap_list[SIGINT]);
  514.       trap_list[SIGINT] = (char *)NULL;
  515.       parse_and_execute (command, "interrupt trap");
  516.       trap_list[SIGINT] = saved_command;
  517.       last_command_exit_value = old_exit_value;
  518.     }
  519. }
  520.